﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Core.Settings;
using Core.Extensions;
using System.Windows.Forms;
using System.Threading;

namespace Settings.Forms
{
    public class HtmlDocumentConverter
    {
        private const string AttrNull = "False";
        private const string BaseUri = "https://by.e-konsulat.gov.pl";

        public PageSettings GetBledySettings()
        {
            return new PageSettings
            {
                Fields = new FieldSettings[] { },
                Headers = this.GetHeaders(),
                ID = (int)KnownPage.Bledy,
                Name = "Bledy.aspx",
                Url = new Uri("https://by.e-konsulat.gov.pl/Bledy/Bledy.aspx")
            };
        }

        public PageSettings GetPodsumowanieSettings()
        {
            return new PageSettings
            {
                Fields = new FieldSettings[] { },
                Headers = this.GetHeaders(),
                ID = (int)KnownPage.Podsumowanie_2,
                Name = "Podsumowanie_2.aspx",
                Url = new Uri("https://by.e-konsulat.gov.pl/Wiza/Podsumowanie_2.aspx")
            };
        }

        public PageSettings ReadSettings(HtmlDocument document)
        {
            if (document == null)
                throw new ArgumentNullException("document");

            document.Assert(document.Forms.Count == 1, "document.Forms.Count == 1");

            HtmlElement form = document.Forms[0];
            PageSettings pageSet = new PageSettings();

            string action = form.GetAttribute("action");
            KnownPage page = KnownPageParser.Parse(action);

            pageSet.ID = (int)page;
            pageSet.Name = page.ToString();
            pageSet.Url = new Uri(new Uri(HtmlDocumentConverter.BaseUri), action);
            pageSet.Fields = this.SearchFields(document.Body).ToArray();
            pageSet.Headers = this.GetHeaders();

            return pageSet;
        }

        public void WriteSettings(HtmlDocument document, PageSettings settings)
        {
            if (document == null)
                throw new ArgumentNullException("document");

            foreach (FieldSettings field in settings.Fields)
            {
                HtmlElement element = document.GetElementById(field.ElementID);

                element.SetAttribute("disabled", field.Disabled ? "disabled" : null);
                switch (field.InputType)
                {
                    case "checkbox":
                    case "radio":
                        if (field.Checked)
                            InvokeScript(document, "SetCheckBox", "#" + field.ElementID, field.Checked);
                        break;
                    default:
                        if (string.IsNullOrEmpty(field.InputValue) == false)
                            InvokeScript(document, "SetValue", "#" + field.ElementID, field.InputValue);
                        break;
                }
            }
        }

        public void InvokeScript(HtmlDocument document, string functionName, params object[] @params)
        {
            document.InvokeScript(functionName, @params);
        }
        public void CleanDocument(HtmlDocument document)
        {
            if (document == null)
                throw new ArgumentNullException("document");

            foreach (var element in document.GetElementsByTagName("input").Cast<HtmlElement>())
            {
                switch (element.GetAttribute("type"))
                {
                    case "checkbox":
                    case "radio":
                        document.InvokeScript("SetCheckBox", new object[] { "#" + element.GetAttribute("id"), false });
                        break;
                    case "text":
                        document.InvokeScript("SetValue", new object[] { "#" + element.GetAttribute("id"), string.Empty });
                        break;
                }
            }
            foreach (var element in document.GetElementsByTagName("select").Cast<HtmlElement>())
            {
                document.InvokeScript("SetValue", new object[] { "#" + element.GetAttribute("id"), string.Empty });
            }
        }

        private Dictionary<string, string> GetHeaders()
        {
            Dictionary<string, string> headers = new Dictionary<string, string>
            {
                {"User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.66 Safari/535.11"},
                {"Accept", "text/html"},
                {"Accept-Language", "ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4"},
                {"Accept-Charset", "windows-1251,utf-8;q=0.7,*;q=0.3"}
            };

            return headers;
        }

        private IEnumerable<FieldSettings> SearchFields(HtmlElement element)
        {
            switch (element.TagName.ToLower())
            {
                case "input":
                case "textarea":
                    FieldSettings input = new FieldSettings();
                    string onclick = element.GetAttribute("onclick");
                    input.AutoPostBack = string.IsNullOrEmpty(onclick) == false && onclick != HtmlDocumentConverter.AttrNull;
                    input.ElementID = element.GetAttribute("id");
                    input.ElementName = element.GetAttribute("name");
                    input.InputValue = element.GetAttribute("value");
                    input.InputType = element.GetAttribute("type") ?? "text";
                    input.Disabled = element.GetAttribute("disabled") != HtmlDocumentConverter.AttrNull;
                    input.Checked = element.GetAttribute("checked") != HtmlDocumentConverter.AttrNull;
                    yield return input;
                    break;
                case "select":
                    FieldSettings select = new FieldSettings();
                    string onchange = element.GetAttribute("onchange");
                    select.AutoPostBack = string.IsNullOrEmpty(onchange) == false && onchange != HtmlDocumentConverter.AttrNull;
                    select.ElementID = element.GetAttribute("id");
                    select.ElementName = element.GetAttribute("name");
                    select.InputValue = string.Join(",", element.Children.OfType<HtmlElement>().Where(option => option.GetAttribute("selected") != HtmlDocumentConverter.AttrNull).Select(option => option.GetAttribute("value")).ToArray());
                    select.InputType = "select";
                    select.Disabled = element.GetAttribute("disabled") != HtmlDocumentConverter.AttrNull;
                    select.Checked = false;
                    yield return select;
                    break;
                default:
                    foreach (HtmlElement child in element.Children.OfType<HtmlElement>())
                    {
                        foreach (FieldSettings field in this.SearchFields(child))
                            yield return field;

                    }
                    break;
            }
        }
    }


}
